/**
 * useCallback()
 *
 *    作用：类似于 useMemo() 不同之处在于 useCallback 缓存的是函数
 *
 *    语法：
 *      const fn = useCallback(函数，deps)
 *        1. 函数 - 需要被缓存的函数
 *        2. deps - 依赖项数组，当依赖项数组发生变化时，缓存会重新执行
 *        3. fn - 缓存的函数
 *
 *    特点：
 *      1. 都需要结合 React.memo() 来玩。
 *
 * 常见的面试问题：useMemo 与 useCallback 的区别：
 *    两者都是 React 的 hook, 都实现的是 缓存。是性能优化的一种手段。
 *    两者语法一致，都是接受一个 函数和一个 deps
 *    不同点：
 *      useMemo 缓存的是 函数的返回值
 *        const xxx = useMemo(() => '张三', [])       xxx = 张三
 *      useCallback 缓存的是 该函数
 *        const xxx = useCallback(() => '张三', [])   xxx = () => '张三'
 *    有个关联
 *
 *        function useCallback(fn, deps) {
 *          return useMemo(() => fn, deps)
 *        }
 */

import { useState, memo, useMemo, useCallback } from "react";

// 处理了 memo 的 Hello
const Hello = memo(function Hello(props) {
  console.log("Hello Render");
  return (
    <div>
      <h4>Hello</h4>
      <button onClick={props.addNum}>num++</button>
    </div>
  );
});

function App() {
  console.log("App Render");
  const [num, setNum] = useState(1);

  // 这样声明 addNum 函数，每次 App 组件重新 Render addNum 都是一份新函数，Hello 组件会重新 Render
  // const addNum = () => {
  //   setNum((num) => num + 1);
  // };

  // 这样声明 addNum 函数，只要 deps 没有变化，该函数是缓存的不会重新创建，给到 Hello 组件，Hello组件内部memo判断prop就是没有发生变化的，所以 Hello 组件不会重新 Render
  // const addNum = useCallback(() => {
  //   setNum((num) => num + 1);
  // }, []);

  // useMemo 与 useCallback 的关联
  const addNum = useMemo(function () {
    return function () {
      setNum((num) => num + 1);
    };
  }, []);

  return (
    <div>
      <h1>App</h1>
      <button onClick={addNum}>{num}</button>
      <hr />
      <Hello addNum={addNum} />
    </div>
  );
}

export default App;
